package com.vvv.designpattern.iterator;

import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author vvv
 * @date 2023-11-27 12 06
 * discription 迭代器模式：EsQueryIterator为具体迭代器
 * 在这里EsQueryIterator的作用是：维护了List<Map>的迭代器iterator和进行es的查询
 */
public class EsQueryIterator implements Iterator<Map<String, Object>> {
    // 当前记录的cursor
    private String cursor;
    // 列名，第一次查询才有
    private List<String> columns;
    /**
     * es返回的数据统一封装到这里，格式为List<Map>: [{"author": "vvv", "name": "vname"}, {"author": "vvv2", "name": "vname2"}]
     * 其中map的key为column
     */
    Iterator<Map<String, Object>> iterator;

    RestTemplate restTemplate = new RestTemplate();

    /**
     * 构造函数进行第一次查询，并初始化cursor，columns
     * @param query
     * @param fetchSize
     */
    public EsQueryIterator(String query, long fetchSize) {
        EsResponseData esResponseData = restTemplate.postForObject(
                "http://localhost:9200/_sql?format=json"
                , new EsSqlQuery(query, fetchSize), EsResponseData.class);
        this.columns = esResponseData.getColumns().stream()
                .map(x -> x.get("name"))
                .collect(Collectors.toList());
        this.iterator = convert(columns, esResponseData).iterator();
    }

    /**
     * 因为在构造函数中进行了第一次查询，所以iterator是有元素的，
     * scrollNext()表示进行第2次查询es
     * @return
     */
    @Override
    public boolean hasNext() {
        return iterator.hasNext() || scrollNext();
    }

    /**
     * 返回迭代器中的数据
     * @return
     */
    @Override
    public Map<String, Object> next() {
        return iterator.next();
    }

    /**
     * 获取第二次及以后的查询结果
     * @return
     */
    private boolean scrollNext() {
        if (iterator == null || cursor == null) {
            return false;
        }
        EsResponseData esResponseData = restTemplate.postForObject(
                "http://localhost:9200/_sql?format=json"
                , new EsSqlQuery(cursor), EsResponseData.class);
        this.cursor = esResponseData.getCursor();
        this.iterator = convert(columns, esResponseData).iterator();
        return iterator.hasNext();
    }

    /**
     * 将es的数据转换为List<Map>
     * @param columns 第一次查询的列名
     * @param esResponseData 这一次查询的es返回的结果
     * @return
     */
    private List<Map<String, Object>> convert(List<String> columns, EsResponseData esResponseData) {
        List<Map<String, Object>> results = new ArrayList<>();
        for (List<Object> row : esResponseData.getRows()) {
            Map<String, Object> map = new HashMap<>();
            for (int i = 0; i < columns.size(); i++) {
                map.put(columns.get(i), row.get(i));
            }
            results.add(map);
        }
        return results;
    }
}
